[contents] [next] [bottom] (1 out of 7)

Chapter 6 - Defining Classes and Objects

Up to this point, discussion has centered on simple examples using existing classes and methods in the ScriptX core classes. ScriptX also allows you to define your own classes, and to specialize individual instances of classes.

Classes and objects created in the ScriptX language using the syntax in this chapter are fully-featured, first-class objects. This means that the ScriptX language, the parser, and the compiler treat user-defined classes and objects in the same way as built-in system classes and objects. This allows you to easily build powerful specialized extensions to ScriptX on top of the core ScriptX implementation.

This chapter describes the syntax for developing new singly- and multiply-inherited classes and objects, and for defining methods and variables within them. It also describes some methods that are commonly overridden in subclasses so that those classes can interact effectively with the language and with other classes in the ScriptX core classes library.

Defining Classes

The most common way to extend the power of ScriptX is to define new subclasses that specialize the existing core classes. You can even create your own hierarchy of classes for whatever application your ScriptX program requires. Defining your own classes allows you to create comprehensive class libraries that can be re-used in any modules and scripts.

Syntax Summary

To define a new class, use the class expression.

class variableName ( classList )
[ class variables
. . . ]
[ instance variables
. . . ]
[ class methods
. . . ]
[ instance methods
. . . ]
end
The class expression has an introductory clause followed by four main sections for defining the features of the new class: class variables, class methods, instance variables, and instance methods. Each part of the expression is described in the following sections.

You must specify the sections of the class expression in the order in which they appear above, although you do not need to include all of them. Use only the sections you need in order to create your specialized subclass. Each section can be on a separate line, as shown in the syntax, or all can be on the same line, or the two styles can be used in any combination.

Classes and Variable Names

The first clause of the class expression specifies the name of the new class and the inheritance of this class.

class variableName ( classList )
. . .
end
lThe variableName part of this line specifies the name of the variable to which this class object will be assigned once it has been created. Like all variables in ScriptX, if the variable named by variableName has not been previously declared, it is automatically declared global. You can specify that the variable name is to be declared locally by putting the reserved word local in front of the reserved word class. Note that just as with local variables, you can only define a local class inside a local scope (that is, not at the top level).

(
	local class SortedLinkedList (LinkedList)
	end
)

This example creates a subclass of the class LinkedList (with no further specialization) and assigns it to the local variable SortedLinkedList.

In addition, the variable to which a class is assigned is declared constant, which means that you cannot assign anything else to it once the class has been created. This is to prevent accidentally overwriting the definition of a class with a simple assignment. You can, however, redefine a class using the name of the original class. (Some restrictions apply; see "A Note on Redefining Classes" on page 113 for more information.)

Classes and Inheritance

The first clause of the class expression also specifies the inheritance of this class.

class variableName ( classList )
. . .
end
The classList, within parentheses, specifies a list of classes from which this class inherits (that this class is a subclass of). The classList can be a single class, or a list of classes separated by commas. If you specify multiple classes in classList, your new class multiply inherits from all those classes. See "Multiple Inheritance" on page 122 for more information on classes with multiple superclasses.

If classList is not specified, (the parentheses are empty), then the class is a direct subclass of RootObject.

A Note on Redefining Classes

You can redefine a class by using the class expression with the same name as a previously-defined class. There are several things to note about redefining classes:

Class and Instance Variables

Class and instance variables specify the properties or state of a given class or object. You can think of class variables as instance variables defined directly on the class object itself. (Technically, that is exactly what they are.)

Instance variables are variables whose values can vary from instance to instance. For example, the class Car may define an instance variable called color. Each instance of Car can then have its own value for color.

Class variables are variables that relate to the class itself, and are accessible to and shared by all the instances of a class, including the class itself. For example, the class LuxuryCar might have a features class variable that holds an array of features common to all instances of luxury cars, such as @antiLockBrakes or @woodPaneling. Those features are shared by all instances of LuxuryCar, and if the value of that variable is ever changed, it affects all those instances equally.

Both class and instance variables are accessed through the use of special generic functions called setters and getters. Setters change (or set) the value of a variable; getters query for (or get) the current value of a variable. ScriptX language constructs for querying and changing class and instance variables are described beginning on page 61. Use these generic functions to indirectly gain access to the variable itself.

ScriptX provides several mechanisms for defining class and instance variables with many different features, including read-only variables, variables that automatically calculate their values when they are queried by some other method in the class or object, or variables that discard their values when stored on disk. Each of these more complex forms for defining variables, as well as details on setter and getter generic functions, is described in detail in "Defining Class and Instance Variables" on page 140.

The simplest way to create a class or instance variable in a class is to use either the class variables or instance variables sections of the class expression.

class variableName ( classList ) 
class variables
varName
varName:initialValue
. . .
instance variables
varName
varName:initialValue
. . .
end
The reserved words class variables can be shortened to class vars. Similarly, the reserved words instance variables can the shortened to inst variables or simply inst vars. Each short form is equivalent to its longer counterpart. After these reserved words, you can specify any number of variable names (here, varName) on separate lines, or all on one line separated by commas, or in any combination.

You can also specify initial values for those variables (initialValue) by supplying a colon and the value after the variable. The initial value of a class variable is assigned when the class is created; the initial value for an instance variable is assigned each time a new instance of that class is created. If you do not specify initial values for a class or instance variable, its value is undefined.

Each of these forms creates "real" instance variables, that is, variables that exist as slots in memory. They also construct pairs of setter and getter functions automatically for each of the variables listed when the class is created. For more details on the setter and getter functions, see "Defining Class and Instance Variables" on page 140.

The following example shows the definition and use of a class variable:

class PurpleDragon ()
class vars numDragons : 0
instance methods
method moreDragons self -> (
(getClass self).numDragons := (getClass self).numDragons + 1
)
end

This example defines a class PurpleDragon. Since no class is specified in the class inheritance list, the class inherits directly from RootObject, the root system class. The PurpleDragon class defines a class variable, numDragons, which is initially set to 0. It also defines an instance method to increase the value of the class variable numDragons by one. Instance methods are described in the section "Class and Instance Methods" on page 116.

Now, you can instantiate PurpleDragon and call moreDragons on any of those instances. The numDragons class variable is increased:

dragon1 := new PurpleDragon
dragon2 := new PurpleDragon
PurpleDragon.numDragons -- the initial value
0 
moreDragons dragon1
1
moreDragons dragon2
2
PurpleDragon.numDragons -- find out new value
2 i

A Note on Class Variables and Inheritance

Class variables, like instance variables, are inherited from class to subclass. However, each class that inherits a class variable from a superclass gets a different version of that class variable; all it inherits is the name. It provides its own "slot" for that variable. This differs from C++, in which class variables are shared by a class, all its instances, and all its subclasses and their instances.

For example, suppose you have a class LuxuryCar, which defines a class variable paneling, whose default value is @oak.

class LuxuryCar ()
	class variables paneling:@oak
end

Now, suppose you created a subclass of LuxuryCar called BargainLuxuryCar. The BargainLuxuryCar class inherits the paneling class variable (and its value) from LuxuryCar:

class BargainLuxuryCar (LuxuryCar) end
BargainLuxuryCar.paneling
@oak

However, because each class owns its own slot for class variables, even inherited ones, if you change the value of LuxuryCar's class variable paneling, BargainLuxuryCar's version of the class variable paneling is not affected.

LuxuryCar.paneling := @teak
@teak
BargainLuxuryCar.paneling
@oak 

Class and Instance Methods

Methods are implementations of generic functions that are defined directly by an object or class, or that are accessible to an object or class through inheritance. Class methods operate on the class object itself, and so are related to the class as a whole (much like class variables). Instance methods operate on an instance of a class. To define class or instance methods, use the class methods or instance methods sections of the class expression:

class variableName ( classList ) 
class methods
methodDefinition
. . .
instance methods
methodDefinition
. . .
end
The reserved words instance methods can be shortened to inst methods; both forms are equivalent.

Both the class methods and instance methods reserved words are followed by any number of individual method definitions. Method definitions are very similar to function definitions-see "Defining Methods" on page 125 for more information.

One of the most commonly defined instance methods is the init method, which determines how an instance of a class is to be initialized when the new method is called on the class. For detailed information on defining initialization methods, see the discussion of the new, init, and afterInit methods that begins on page 132.


This document is part of the ScriptX Language Guide, one of the volumes of the ScriptX Technical Reference Series. ScriptX is developed by the ScriptX Engineering Team at Apple Computer, successor to the Kaleida Engineering Team at Kaleida Labs, Inc.

Copyright 1996 Apple Computer, Inc. All Rights Reserved.